Calling OpenTransport from a code resource can be tricky. This package demonstrates how to do it using both Metrowerks C and Symantec C for MPW. The package contains the files necessary to build a HyperCard XCMD that displays the default Ethernet address for the machine using OpenTransport native calls.
The Package
The package includes the following files:
• Read Me — OT Code Resource — This file.
• OTGetDefaultEthernetAddress.c — C source code for the XCMD.
• OTGetDefaultEtherAddr.µ — CodeWarrior Pro 1 project for the XCMD.
• Worksheet — Instructions for building the XCMD in MPW.
• OTGetDefaultEthernetAddr — Another HyperCard stack to test the build results. This stack includes two built versions of the XCMD, one built with Metrowerks, the other with Symantec C for MPW.
• ApplParamsHack.c — A C source file that creates the AppParams global for the Metrowerks build. See below for details.
• ApplParamsHack.c.o — An object file compiled from the above.
I tested this sample on a Power Macintosh 6500/250 running Mac OS 8.1 (OT 1.3).
Requirements
To use this code you will need:
1. HyperCard or HyperCard Player — Any version should beyond 2.0 should work fine.
2. OpenTransport 1.3 SDK — This is available on the Mac OS SDK CDs.
3. [Metrowerks only] Metrowerks CodeWarrior Pro 1 — It may work with earlier or later versions but I haven’t tried. [Actually, I just tried it with CodeWarrior Pro 2 and everything seems to be fine.]
4. [SC only] ETO 23 — It may work with earlier versions but I haven’t tried.
5. [SC only] ASLM 2.0 SDK — This is available on the Mac OS SDK CDs.
Issues
There are a number of issues related to calling OT from a code resource. The first is just getting the code resource to link. This is surprisingly tricky because the OT libraries contain global data with initialisers that causes problems for a number of development environments when they’re creating a code resource.
The second problem is creating an A5 world. OT requires that each client (ie program calling it) create its own A5 world and have OT globals allocated in that A5 world. This is really easy if you’re building an application but a total pain when building a code resource.
Metrowerks Code
Special Considerations
CodeWarrior uses an A4 world to access global variables inside a code resource. The OpenTransport 68K libraries are all A5 relative, which might seem like a problem. This code demonstrates a workaround for that problem.
The A5 relative bits of the OT libraries boil down to code and data references. The code references are of the form:
JSR $xxxx(A5)
The CodeWarrior ".o" file conversion process converts these to:
JSR $xxxx(A4)
… which the CodeWarrior linker converts to PC relative addresses, ie:
JSR $xxxx(PC)
The other problem is the data references. These are of the form:
LEA $xxxx(A5),A0
MOVE.L $xxxx(A5),D0
...
… and so on. The CodeWarrior ".o" file conversion process leaves these files unchanged but the linker changes the offsets (ie $xxxx in the listings above) to the correct offsets from A4 to the relevant data sections. This means that all you need to do is keep A5 pointing to the same location as A4 and everything will be fine.
Coding Considerations
This introduces a number of complication to your code. When you enter the code resource you must preserve the value of A5 (using the GetCurrentGlobalWorld inlines) , initialise the CodeWarrior globals (by calling the CodeWarrior SetCurrentA4 routine) and then set the value of A5 to the value of A4 using SynchGlobalWorldFromA4 .
On exit you must undo the damage, restoring A5 to the original value (using SetCurrentGlobalWorld) as well as calling CodeWarrior’s SetA4 routine to restore A4 to its original value.
The sample code demonstrates this process.
Another problem you might encounter is inside OT notification routines. When OT calls your notifier it automagically sets A5 to the value it had when you called OTInstallNotifier. You must also set the A4 register to that value so that CodeWarrior code can access its globals. You can do this using the CodeWarrior "SetupA4.h" library or by calling SynchA4FromGlobalWorld. Don’t forget to preserve the old value of A4 lest you upset OT, which expects A4 to be preserved by callbacks.
ASLM Causing Trouble Again
The sample also deals with a little known weirdness in Apple Share Library Manager. When linking in MPW the first 32 bytes above A5 are automatically allocated for application parameters. The only well-documented use of the application parameters is that the first 4 bytes are used to hold a pointer to the QuickDraw globals, set up by the InitGraf routine. However ASLM uses the next four bytes (location 4(A5)) to hold a reference to the TLibraryManager object associated with the global world. As far as I know, this behaviour was previously undocumented, and it certainly causes problems for this sample.
Note: You can read more about application parameters and the A5 world in "Inside Macintosh: Memory", specifically Figure 1-6 at the following URL:
I work around this problem by forcing CodeWarrior to allocate 32 bytes of otherwise unused storage as the first thing in its A4 globals, and hence as the first 32 bytes of its A5 world. Doing this is surprisingly tricky. CodeWarrior Pro 1 allocates A4 world storage for imported MPW ".o" files before it allocates the storage for native CodeWarrior code. As the OT libraries are ".o" files which contain global variables — and you don't want them to be placed first in the A5 world — you have to allocate this extra storage by importing an MPW ".o" file that contains the storage. The sample supplies this ".o" file, called "ApplParamsHack.c.o".
You also have to make sure that the CodeWarrior linker doesn’t “dead strip” this variable, ie eliminate it because there are no references to it. I do this by taking the address of the variable and storing it in a pointer in the code resource’s main function.
Once you’ve built your code, you should use a link map file to determine whether this has worked correctly. Create the link map by checking Generate Link Map in the 68K Linker preferences panel. Then build your project, which will create a “.MAP” file in the same directory as your project. Towards the end of the link map file, you will find the table of initialised near data.
Initialized near data
Data: 0 32 bytes "ZZZApplParamsHack"
You want to ensure that ZZZApplParamsHack is the first entry in this table and has offset 0 above A4.
Project Considerations
The project has the following CodeWarrior attributes:
• It links with the near libraries (ie OpenTransport.n.o and OpenTransportExtn.n.o) not the far libraries. I’ve heard reports that the far libraries also work just fine, although I haven’t tested it myself.
• It has 4 byte integers set, always a good idea IMHO.
• It links with Model Near “MSL Runtime68K.A4.Lib” because we want A4 relative globals. This version of the sample (1.0.1) no longer uses the standard C libraries.
• I set the following non-default options: Small Code Model in the 68K Processor panel, Link Single Segment in the 68K Linker panel, and Code Resource and Extended Resource in the 68K Project panel. Some of these are not required but I got a working system and I didn’t want to mess with it. The key option is definitely the Extended Resource option.
Symantec Code
Coding Considerations
There is a classic Macintosh Technote called “PT 35 Stand Alone Code, ad nauseam” <http://dev.info.apple.com/dev/technotes/pt/pt_35.html> which describes the mechanism for getting your own global (ie A5) world from stand alone code. This is recommended reading for anyone who wants to mess around with 68K standalone code.
Fortunately however much of the technology in this technote is embodied in the ASLM utility routines provided in LibraryManagerUtilities.[ph]. Rather than reinvent the wheel, I simply call these routines (GetCurrentGlobalWorld, InitCodeResource, SetCurrentGlobalWorld and FreeGlobalWorld) to create, use and tear down a global world. This makes the task surprisingly easy.
Linking Requirements
That is not to say that working out this stuff was easy. Specifically you have to be very exact about the options you pass to the MPW Link tool to create your code resource. If you encounter strange linking problems, check your options against mine. My biggest problems were:
1. Forgetting to specify -t XXXX -c XXXX, which caused the tool to think it was creating an application (even though I had passed the -rt option!) which caused very bizarre linking errors.
2. Forgetting to specify a main entry point (ie -m MAIN) which caused very strange linking problems.
I’m sure an MPW guru could explain this [Hey, I thought I was an MPW guru!] but for most people these points are just something to avoid.
Other Compilers
I have only done a little bit of investigating of how to OT from a code resource with other compilers. I don’t think it’s possible to do it from the Think Project Manager because of a problem with it’s .o file importing tool. Doing it from PowerPC environments is most probably a lot easier because the PPC has a single runtime architecture shared by all compilers. But beyond that I’m in the dark. I hope that this package will cover most people’s requirements.
Credits and Version History
If you find any problems with this stuff, mail <DevSupport@apple.com> with “Attn: Quinn” as the first line of your mail and I’ll try to fix them up.
Version 1.0b2 is the first widely distributed version.
Version 1.0.1d1 (Nov 1997) was distributed to a small number of developers while trying to work out a bug related to ASLM’s use of 4(A5).
Version 1.0.1b1 (Mar 1998) is a new version that addresses the 4(A5) problem and generally tidies up the code for the new world. If you’ve used a previous version of this sample, you should read and understand the “ASLM Causing Trouble Again” section of this document!
Share and Enjoy.
Quinn “The Eskimo!”
Apple Developer Technical Support
Networking, Communications, Hardware
13 Mar 1998 [Friday the 13th! An appropriate day to be releasing this sample (-: ]